package ray.shader;

import java.util.ArrayList;
import ray.Intersection;
import ray.Ray;
import ray.Scene;
import ray.Light;
import ray.math.Color;
import ray.math.Vector3;

public class Glass extends Shader {
        
    protected double refractiveIndex;
    public void setRefractiveIndex(double refractiveIndex) { this.refractiveIndex = refractiveIndex; }
        
    public Glass() { }
        
    /**
     * Calculate the BRDF value for this material at the intersection described in record.
     * Returns the BRDF color in outColor.
     * @param outColor Space for the output color
     * @param scene The scene
     * @param lights The lights
     * @param toEye Vector pointing towards the eye
     * @param record The intersection record, which hold the location, normal, etc.
     * @param depth The depth of recursive calls.
     * @param contribution The contribution of the current ray.
     * @param internal You can ignore this for glazed.
     */
    @Override
    public void shade(Color outColor, Scene scene, ArrayList<Light> lights, Vector3 toEye, Intersection record, int depth, double contribution, boolean internal)
    {
        if (internal)
                {
                        record.normal.scale(-1);
                }
        double dp = toEye.dot(record.normal);
        

        if (depth <= Shader.MAXDEPTH && contribution >= Shader.MINCONTRIBUTION && dp > 0)
        {
                
                double r0 = ((refractiveIndex - 1)*(refractiveIndex - 1)) / ((refractiveIndex + 1) * (refractiveIndex + 1));
                double myWeight = r0 + (1-r0)*Math.pow(1-dp, 5);
                myWeight = 1 - myWeight;
                
                //Shoot a refracting ray
                double n_over_nt;
                if (internal)
                {
                        n_over_nt = refractiveIndex;
                }
                else
                {
                        n_over_nt = 1/refractiveIndex;
                }
                double normal_coeff_squared = (1 - (n_over_nt)*(n_over_nt)*(1-dp*dp));
                if (normal_coeff_squared < 0)
                {
                        //total internal reflection
                        myWeight = 0;
                }
                else
                {
                        Ray refractingRay = new Ray(record.intersection, toEye);
                        refractingRay.d.scale(-1);
                        refractingRay.d.scale(n_over_nt);
                        refractingRay.d.scaleAdd( n_over_nt*dp - Math.sqrt(normal_coeff_squared), record.normal);
                        /*
                        else
                        {
                                refractingRay.direction.set(record.normal);
                                refractingRay.direction.scale(dp);
                                refractingRay.direction.scaleAdd(-n_over_nt, toEye);
                                refractingRay.direction.scaleAdd(-dp*n_over_nt, record.normal);
                        }*/
                        refractingRay.d.normalize();
                        refractingRay.makeOffsetRay();
                        
                        Intersection refractionRecord = new Intersection();
                        scene.getFirstIntersection(refractionRecord, refractingRay);
                        
                        if (refractionRecord.surface != null)
                        {
                                refractingRay.d.scale(-1); //toEye for refracting ray
                                refractionRecord.surface.getShader().shade(outColor, scene, lights, refractingRay.d, refractionRecord, depth+1, contribution * myWeight, !internal);
                        }
                    }
                
                //Shoot a reflection ray
                Ray reflectionRay = new Ray(record.intersection, record.normal);
                reflectionRay.d.scale(2*dp);
                reflectionRay.d.sub(toEye);
                reflectionRay.d.normalize();
                
                reflectionRay.makeOffsetRay();
                Intersection eyeRecord = new Intersection();
                
                        scene.getFirstIntersection(eyeRecord, reflectionRay);
                        if (eyeRecord.surface != null)
                        {

                        reflectionRay.d.scale(-1); //should actually create a new variable for reflectionToEye, but this is more efficient
                                
                        eyeRecord.surface.getShader().shade(outColor, scene, lights, reflectionRay.d, eyeRecord, depth+1, contribution * (1-myWeight), internal);
                        }
                        else
                        {
                                //there might be background color stuff going on here
                                outColor.r += 0.0 * (1 - myWeight);
                                outColor.g += 0.0 * (1 - myWeight);
                                outColor.b += 0.0 * (1 - myWeight);
                        }
        }
    }
    
    
}
